package com.jing.android.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 *
 * @author JingTuo
 */
public class AppStartTime {

    private static final String OS_VERSION_10 = "10";

    private static final String OS_VERSION_7 = "7";

    private static final String OS_VERSION_6 = "6";

    private static final String TAG_AM = "ActivityManager";

    private static final String TAG_AT = "ActivityThread";

    private static final String TAG_ATM = "ActivityTaskManager";

    private static final String START_ACTIVITY_PREFIX = "startActivityMayWait";
    private static final String CREATE_ACTIVITY_PREFIX = "ActivityThread,callActivityOnCreate";
    private static final String ACTIVITY_DISPLAYED_PREFIX = "Displayed";

    private static final String START_ACTIVITY_PREFIX_OS_7 = "START";

    private static final String START_ACTIVITY_PREFIX_OS_10 = "START";

    private static final String ACTIVITY_IDLE_PREFIX = "Activity idle:";

    private static final String CELL_SPLIT = ",";
    private static final String ROW_SPLIT = "\n";
    private static final String DATE_EMPTY = "--";

    private static final int STATE_NONE = 0;
    private static final int STATE_SPLASH_START = 1;
    private static final int STATE_SPLASH_CREATED = 2;
    private static final int STATE_SPLASH_END = 3;
    private static final int STATE_MAIN_START = 4;
    private static final int STATE_MAIN_END = 5;


    public static void main(String[] args) {
        if (args == null || args.length <= 0) {
            System.err.println("统计启动耗时,目前仅在华为P9验证通过,请输入参数:");
            System.err.println("参数1: 日志文件路径");
            System.err.println("参数2: 统计数据存储路径(不需要指定到文件,文件名按照日期时间生成,精确到秒)");
            System.err.println("参数3: Splash页面(如: 包名(applicationId)/页面完整类名");
            System.err.println("参数4: Main页面(如: 包名(applicationId)/页面完整类名");
            System.err.println("参数4: 安卓系统版本(如: 6, 7, 10");
            return;
        }
        int length = args.length;
//        String logPath = "/Users/jingtuo/Documents/Log/20210308-4.log";
        String logPath = args[0];
        String exportPath = "/Users/jingtuo/Documents/办公文档/启动优化/";
        if (length >= 2) {
            exportPath = args[1];
        }
        String splash = "com.foundersc.app.xf/com.hundsun.winner.application.hsactivity.splash.SplashActivity";
        if (length >= 3) {
            splash = args[2];
        }
        String main = "com.foundersc.app.xf/com.foundersc.app.module.main.MainActivity";
        if (length >= 4) {
            main = args[3];
        }
        String osVersion = OS_VERSION_6;
        if (length >= 5) {
            osVersion = args[4];
        }
        System.out.println("开始导出数据>>>>>>>>>>>>>>>>>>>>>");
        try {
            BufferedReader br = new BufferedReader(new FileReader(logPath));
            File exportFolder = new File(exportPath);
            if (!exportFolder.exists()) {
                //noinspection ResultOfMethodCallIgnored
                exportFolder.mkdirs();
            }
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
            String fileName = dateFormat.format(new Date(System.currentTimeMillis())) + ".csv";
            File exportFile = new File(exportFolder, fileName);
            System.out.println("输出文件名:" + exportFile.getAbsolutePath());
            FileWriter writer = new FileWriter(exportFile);
            StringBuilder builder = new StringBuilder();
            if (OS_VERSION_10.equals(osVersion)) {
                handleAndroidOS10(br, splash, main, builder);
            } else if (OS_VERSION_7.equals(osVersion)) {
                //Nexus 5X 7.0(API 24)
                handleAndroidOS7(br, splash, main, builder);
            } else {
                handleAndroidOS6(br, splash, main, builder);
            }
            writer.write(builder.toString());
            writer.flush();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<导出数据结束");
    }

    /**
     * 处理安卓系统版本7.0,仅在Nexus 5x(7.0)测试通过
     * @param br
     * @param splash
     * @param main
     * @param output
     * @throws Exception
     */
    private static void handleAndroidOS7(BufferedReader br, String splash, String main, StringBuilder output) throws Exception {
        output.append("Splash启动时间,Main启动时间,启动-Main耗时,Main显示时间,Main显示耗时,启动总耗时")
                .append(ROW_SPLIT);
        int splashStartTime = 0;
        int mainStartTime = 0;
        int mainDisplayedTime = 0;
        int state = STATE_NONE;
        StringBuilder rowBuilder = null;
        while (true) {
            String line = br.readLine();
            if (line == null) {
                //结束
                break;
            }
            //1.0版本只考虑在华为P9手机上
            if (line.contains(TAG_AM) && line.contains(START_ACTIVITY_PREFIX_OS_7)) {
                if (line.contains(splash)) {
                    //统计-Splash启动时间
                    state = STATE_SPLASH_START;
                    rowBuilder = new StringBuilder();
                    String time = extractTime(line);
                    //多增加个空格,避免在WPS中自动转换成时间格式导致的显示异常
                    rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                    splashStartTime = convertToMs(time);
                }
                if (line.contains(main)) {
                    //统计-Main启动时间,Main-Splash之间耗时
                    if (STATE_SPLASH_START == state) {
                        //在安卓7.0不出现Displayed Splash
                        state = STATE_MAIN_START;
                        String time = extractTime(line);
                        rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                        mainStartTime = convertToMs(time);
                        rowBuilder.append(mainStartTime - splashStartTime).append(CELL_SPLIT);
                    }
                }
            }
            if (line.contains(TAG_AM) && line.contains(ACTIVITY_DISPLAYED_PREFIX)) {
                if (line.contains(main)) {
                    //统计-Main显示时间,Main显示耗时,启动总耗时
                    if (STATE_MAIN_START == state) {
                        state = STATE_MAIN_END;
                        String time = extractTime(line);
                        rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                        mainDisplayedTime = convertToMs(time);
                        rowBuilder.append(mainDisplayedTime - mainStartTime).append(CELL_SPLIT);
                        rowBuilder.append(mainDisplayedTime - splashStartTime).append(ROW_SPLIT);
                        //只有匹配main页面结束,才算一条完整的数据
                        String rowData = rowBuilder.toString();
                        System.out.println(rowData);
                        output.append(rowData);
                        state = STATE_NONE;
                        rowBuilder = null;
                    }
                }
            }
        }
    }




    /**
     * 处理安卓系统版本6.0,仅在华为P9上测试通过
     * @param br
     * @param splash
     * @param main
     * @param output
     * @throws Exception
     */
    private static void handleAndroidOS6(BufferedReader br, String splash, String main, StringBuilder output) throws Exception {
        output.append("Splash启动时间,Splash-Create时间,Splash被Created之前耗时,Splash显示时间,Splash显示耗时," +
                "Main启动时间,Main-Splash之间耗时,Main显示时间,Main显示耗时,启动总耗时")
                .append(ROW_SPLIT);
        int splashStartTime = 0;
        int splashAddTime = 0;
        int splashDisplayedTime = 0;
        int mainStartTime = 0;
        int mainDisplayedTime = 0;
        int state = STATE_NONE;
        StringBuilder rowBuilder = null;
        while (true) {
            String line = br.readLine();
            if (line == null) {
                //结束
                break;
            }
            if (line.contains(TAG_AM) && line.contains(START_ACTIVITY_PREFIX)) {
                if (line.contains(splash)) {
                    //统计-Splash启动时间
                    state = STATE_SPLASH_START;
                    rowBuilder = new StringBuilder();
                    String time = extractTime(line);
                    //多增加个空格,避免在WPS中自动转换成时间格式导致的显示异常
                    rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                    splashStartTime = convertToMs(time);
                }
                if (line.contains(main)) {
                    //统计-Main启动时间,Main-Splash之间耗时
                    if (STATE_SPLASH_CREATED == state) {
                        //当Splash页面很快跳过时,不会出现Displayed
                        //写入Splash显示时间,Splash显示耗时
                        rowBuilder.append(DATE_EMPTY).append(CELL_SPLIT);
                        rowBuilder.append(DATE_EMPTY).append(CELL_SPLIT);
                        state = STATE_MAIN_START;
                        String time = extractTime(line);
                        rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                        mainStartTime = convertToMs(time);
                        rowBuilder.append(mainStartTime - splashAddTime).append(CELL_SPLIT);
                    }
                    if (STATE_SPLASH_END == state) {
                        //只有前一个状态是splash页面结束,才记录main页面
                        state = STATE_MAIN_START;
                        String time = extractTime(line);
                        rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                        mainStartTime = convertToMs(time);
                        rowBuilder.append(mainStartTime - splashDisplayedTime).append(CELL_SPLIT);
                    }
                }
            }
            if (line.contains(TAG_AT) && line.contains(CREATE_ACTIVITY_PREFIX)) {
                if (STATE_SPLASH_START == state) {
                    //统计-Splash-Add时间,Splash被Add之前耗时
                    state = STATE_SPLASH_CREATED;
                    String time = extractTime(line);
                    rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                    splashAddTime = convertToMs(time);
                    rowBuilder.append(splashAddTime - splashStartTime).append(CELL_SPLIT);
                }
            }
            if (line.contains(TAG_AM) && line.contains(ACTIVITY_DISPLAYED_PREFIX)) {
                if (line.contains(splash)) {
                    //统计-Splash显示时间,Splash显示耗时,
                    if (STATE_SPLASH_CREATED == state) {
                        state = STATE_SPLASH_END;
                        String time = extractTime(line);
                        rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                        splashDisplayedTime = convertToMs(time);
                        rowBuilder.append(splashDisplayedTime - splashAddTime).append(CELL_SPLIT);
                    }
                }
                if (line.contains(main)) {
                    //统计-Main显示时间,Main显示耗时,启动总耗时
                    if (STATE_MAIN_START == state) {
                        state = STATE_MAIN_END;
                        String time = extractTime(line);
                        rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                        mainDisplayedTime = convertToMs(time);
                        rowBuilder.append(mainDisplayedTime - mainStartTime).append(CELL_SPLIT);
                        rowBuilder.append(mainDisplayedTime - splashStartTime).append(ROW_SPLIT);
                        //只有匹配main页面结束,才算一条完整的数据
                        String rowData = rowBuilder.toString();
                        System.out.println(rowData);
                        output.append(rowData);
                        state = STATE_NONE;
                        rowBuilder = null;
                    }
                }
            }
        }
    }


    /**
     * 处理安卓系统版本1.0,仅在华为P30 Pro上测试通过
     * @param br
     * @param splash
     * @param main
     * @param output
     * @throws Exception
     */
    private static void handleAndroidOS10(BufferedReader br, String splash, String main, StringBuilder output) throws Exception {
        output.append("Splash启动时间,Splash-Add时间,Splash被Add之前耗时,Splash显示时间,Splash显示耗时," +
                "Main启动时间,Main-Splash之间耗时,Main显示时间,Main显示耗时,启动总耗时")
                .append(ROW_SPLIT);
        int splashStartTime = 0;
        int splashAddTime = 0;
        int splashDisplayedTime = 0;
        int mainStartTime = 0;
        int mainDisplayedTime = 0;
        int state = STATE_NONE;
        StringBuilder rowBuilder = null;
        while (true) {
            String line = br.readLine();
            if (line == null) {
                //结束
                break;
            }
            if (line.contains(TAG_ATM) && line.contains(START_ACTIVITY_PREFIX_OS_10)) {
                if (line.contains(splash)) {
                    //统计-Splash启动时间
                    state = STATE_SPLASH_START;
                    rowBuilder = new StringBuilder();
                    String time = extractTime(line);
                    //多增加个空格,避免在WPS中自动转换成时间格式导致的显示异常
                    rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                    splashStartTime = convertToMs(time);
                }
                if (line.contains(main)) {
                    //统计-Main启动时间,Main-Splash之间耗时
                    if (STATE_SPLASH_END == state) {
                        //只有前一个状态是splash页面结束,才记录main页面
                        state = STATE_MAIN_START;
                        String time = extractTime(line);
                        rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                        mainStartTime = convertToMs(time);
                        rowBuilder.append(mainStartTime - splashDisplayedTime).append(CELL_SPLIT);
                    }
                }
            }
            if (line.contains(CREATE_ACTIVITY_PREFIX)) {
                if (STATE_SPLASH_START == state) {
                    //统计-Splash-Add时间,Splash被Add之前耗时
                    state = STATE_SPLASH_CREATED;
                    String time = extractTime(line);
                    rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                    splashAddTime = convertToMs(time);
                    rowBuilder.append(splashAddTime - splashStartTime).append(CELL_SPLIT);
                }
            }
            if (line.contains(TAG_ATM) && line.contains(ACTIVITY_IDLE_PREFIX)) {
                if (line.contains(splash)) {
                    //统计-Splash显示时间,Splash显示耗时,
                    if (STATE_SPLASH_CREATED == state) {
                        state = STATE_SPLASH_END;
                        String time = extractTime(line);
                        rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                        splashDisplayedTime = convertToMs(time);
                        rowBuilder.append(splashDisplayedTime - splashAddTime).append(CELL_SPLIT);
                    }
                }
                if (line.contains(main)) {
                    //统计-Main显示时间,Main显示耗时,启动总耗时
                    if (STATE_MAIN_START == state) {
                        state = STATE_MAIN_END;
                        String time = extractTime(line);
                        rowBuilder.append(" ").append(time).append(CELL_SPLIT);
                        mainDisplayedTime = convertToMs(time);
                        rowBuilder.append(mainDisplayedTime - mainStartTime).append(CELL_SPLIT);
                        rowBuilder.append(mainDisplayedTime - splashStartTime).append(ROW_SPLIT);
                        //只有匹配main页面结束,才算一条完整的数据
                        String rowData = rowBuilder.toString();
                        System.out.println(rowData);
                        output.append(rowData);
                        state = STATE_NONE;
                        rowBuilder = null;
                    }
                }
            }
        }
    }

    /**
     * 提取时间,忽略日期
     *
     * @param oneLineLog
     * @return
     */
    private static String extractTime(String oneLineLog) {
        int startIndex = oneLineLog.indexOf(" ");
        int endIndex = oneLineLog.indexOf(" ", startIndex + 1);
        return oneLineLog.substring(startIndex + 1, endIndex);
    }

    /**
     * @param time
     * @return
     */
    private static int convertToMs(String time) {
        String hourStr = time.substring(0, 2);
        String minuteStr = time.substring(3, 5);
        String secondStr = time.substring(6, 8);
        String msStr = time.substring(9, 12);
        int hour = Integer.parseInt(hourStr);
        int minute = Integer.parseInt(minuteStr);
        int second = Integer.parseInt(secondStr);
        int ms = Integer.parseInt(msStr);
        return (hour * 3600 + minute * 60 + second) * 1000 + ms;
    }

}